//
//  ClubPushForumViewController.swift
//  77Club
//
//  Created by Apple on 2025/1/2.
//

import UIKit
import ZLPhotoBrowser
import Photos
import AVFoundation

class ClubPushForumViewController: ClubBaseViewController, RaeAnimationProtocol {

    private let scrollView = UIScrollView()
    private let containerView = UIView()
    private let closeButton = c_make_ex(UIButton.self)
        .image("Common_close").end()
    private let titleLabel = c_make_ex(UILabel.self)
        .text("发布到圈子").font(16.font_semiBold).color(.black).end()
    private let sendButton = c_make_ex(UIButton.self)
        .image("Square_pushEnable").image("Square_pushDisable", state: .disabled).end()
    private let iconImageView = c_make_ex(UIImageView.self)
        .corner(18.0.Scale).border(.black.alpha(0.1), width: 1.5).end()
    let titleTextField = c_make_ex(UITextField.self)
        .bgColor(.clear).color("#47494D").font(16.font_semiBold)
        .placeholder("在此处输入标题").end()
    private let placeholderLabel = c_make_ex(UILabel.self)
        .text("在此处输入内容...").font(15.font_regular).color("#AEB0B3").end()
    // 创建UITextView
    private let textView: UITextView = {
        let tv = UITextView()
        tv.font = 15.font_regular
        tv.textColor = "#47494D".toColor
        tv.tintColor = "#47494D".toColor
//        tv.isScrollEnabled = false  // 禁止滚动
        tv.backgroundColor = .clear
        tv.translatesAutoresizingMaskIntoConstraints = false
        return tv
    }()
    private let topicView = ClubPushForumTopicView()
    private let functionView = ClubDynamicFunctionView()
    private let searchView = ClubDynamicSearchView()
    private let collectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewFlowLayout())
    
    var gameModels: [ClubDynamicGameModel]?
    var topicModels: [ClubDynamicGameModel]?
    
    var images: [UIImage] = []{
        didSet{
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
                self.loadImageData()
            }
        }
    }
    var assets: [PHAsset] = []
    private var imageUrlArr = [String]()
    var subject_id: [String] = []
    var gid: [String] = []
    var post_id: [String] = []
    private var oldText: NSAttributedString?
    // 定义富文本的范围
    var richTextRange = [NSRange]()
    var updateData: (() -> Void)?
    var tempArray = [ClubDynamicGameModel]()
    
    private var classID: String = "4" //4攻略  2问题
    var fromDraft = false
    var communityId: String = ""
    //1.图文 2.视频
    var type = 1 {
        didSet{
            if type == 1 {
                titleLabel.text = "发图文"
            }else{
                titleLabel.text = "发视频"
            }
        }
    }
    
    var contentStr: String = "" {
        didSet{

            textView.attributedText = createAttributedText(from: contentStr)
            oldText = textView.attributedText
            
            DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                // 计算文本内容的高度
                let size = CGSize(width: self.textView.frame.width, height: .infinity)
                let estimatedSize = self.textView.sizeThatFits(size)
                // 更新高度约束
                if estimatedSize.height > 248.0.Scale {
                    self.textView.heightConstraint?.constant = 248.0.Scale
                }else{
                    self.textView.heightConstraint?.constant = estimatedSize.height
                }
                self.placeholderLabel.isHidden = !self.textView.text.isEmpty
                self.updateSendState()
            }
        }
    }
    
    var updateDataBlock: (() -> Void)?
    
    init() {
        super.init(nibName: nil, bundle: nil)
        modalPresentationStyle = .fullScreen
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    deinit {
        NotificationCenter.default.removeObserver(self)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        view.subviews{
            scrollView.subviews{
                containerView.subviews{
                    iconImageView
                    titleTextField
                    textView.subviews{
                        placeholderLabel
                    }
                    topicView
                    functionView
                    collectionView
                }
            }
            closeButton
            titleLabel
            sendButton
            searchView
        }
        
        scrollView.backgroundColor = .clear
        containerView.backgroundColor = .clear
        scrollView.top(0).leading(0).width(.screenWidth).bottom(0)
        containerView.fillContainer().width(.screenWidth)
        closeButton.top(.statusHeight).leading(0).width(56.0.Scale).height(44.0.Scale)
        titleLabel.Leading == closeButton.Trailing
        titleLabel.CenterY == closeButton.CenterY
        sendButton.trailing(0).top(.statusHeight).height(44.0.Scale).width(88.0.Scale)
        iconImageView.leading(10).top(.navi_height+4.0).size(36.0.Scale)
        titleTextField.leading(56.0.Scale).trailing(12.0.Scale).height(24.0.Scale).top(.navi_height+8.0.Scale)
        textView.leading(52.0.Scale).trailing(12.0.Scale).top(.navi_height+36.0.Scale).height(37.0.Scale)
        placeholderLabel.leading(6).top(4)
        topicView.leading(56.0.Scale).trailing(12.0.Scale).height(24.0.Scale)
        topicView.Top == textView.Bottom + 3.0.Scale
        functionView.leading(56.0.Scale).trailing(0).height(33.0.Scale)
        functionView.Top == topicView.Bottom + 10.0.Scale
        searchView.leading(0).trailing(0).bottom(0)
        searchView.Top == textView.Bottom
        collectionView.leading(0).trailing(0).height(0).bottom(.tabBar_height)
        collectionView.Top == functionView.Bottom + 8.0.Scale
        
        titleTextField.placehold("#AEB0B3".toColor, font: 16.font_semiBold)
        titleTextField.delegate = self
        sendButton.isEnabled = false
        textView.delegate = self
        searchView.isHidden = true
        placeholderLabel.translatesAutoresizingMaskIntoConstraints = false
        closeButton.addTarget(self, action: #selector(clickCloseButton), for: .touchUpInside)
        if type == 1 {
            functionView.imgStr = ["Square_pushGame","Square_pushTopic","Square_pushPic","Square_pushPost"]
        }else{
            functionView.imgStr = ["Square_pushGame","Square_pushTopic","Square_pushVideo","Square_pushPost"]
        }
        
        let layout = UICollectionViewFlowLayout()
        layout.minimumLineSpacing = 2.0.Scale
        layout.minimumInteritemSpacing = 2.0.Scale
        layout.scrollDirection = .vertical
        layout.sectionInset = UIEdgeInsets(top: 0, left: 56.0.Scale, bottom: 0, right: 16.0.Scale)
        
        collectionView.collectionViewLayout = layout
        collectionView.backgroundColor = .clear
        collectionView.register(ClubGameCircleCell.self, forCellWithReuseIdentifier: ClubGameCircleCell.description())
        collectionView.showsVerticalScrollIndicator = false
        collectionView.delegate = self
        collectionView.dataSource = self
        
        functionView.functionButtonBlock = { funcID in
            
            if funcID == 0 {
                
                self.searchView.isHidden = false
                self.searchView.searchType = 2
                self.functionView.isHidden = true
            } else if funcID == 1 {
                
                self.searchView.isHidden = false
                self.searchView.searchType = 1
                self.functionView.isHidden = true
            } else if funcID == 2 {
                //添加图片、视频
                self.checkPhotoLibraryPermission()
            } else if funcID == 3 {
                //帖子
                self.searchView.isHidden = false
                self.searchView.searchType = 3
                self.functionView.isHidden = true
            }
            
            self.textView.resignFirstResponder()
        }
        
        searchView.searchBlock = { md in
            
            if !self.searchView.isHidden {
                self.searchView.isHidden = true
                self.functionView.isHidden = false
            }
            if md.type == "2" {
                //游戏
//                self.gid.append(md.id)
                self.insertRichText(in: self.textView, image: "Square_gameTag".toImage, model: md, textColor: "#3D9399".toColor, imageSize: CGSizeMake(20, 20))
                self.textView.becomeFirstResponder()
            }else if md.type == "1"{
                //话题
//                self.subject_id.append(md.id)
                self.insertRichText(in: self.textView, image: nil, model: md, textColor: "#E57617".toColor, imageSize: .zero)
                self.textView.becomeFirstResponder()
            }else if md.type == "3"{
                //帖子
//                self.post_id.append(md.id)
                self.insertRichText(in: self.textView, image: nil, model: md, textColor: "#1280E5".toColor, imageSize: .zero)
                self.textView.becomeFirstResponder()
            }
        }
        topicView.selTopicBlock = { md in
            //话题
            self.subject_id.append(md.id)
            self.insertRichText(in: self.textView, image: nil, model: md, textColor: "#E57617".toColor, imageSize: .zero)
            self.textView.becomeFirstResponder()
        }
        searchView.isShowSearchView = {
            if !self.searchView.isHidden {
                self.searchView.isHidden = true
                self.functionView.isHidden = false
            }
        }
        
        iconImageView.loadImage(url: ClubUser.face)
        sendButton.addTarget(self, action: #selector(clickSendButton), for: .touchUpInside)
        // 监听键盘弹起通知
//        NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
    }
}

//MARK: action
extension ClubPushForumViewController {
    
    private func checkPhotoLibraryPermission() {
         let status = PHPhotoLibrary.authorizationStatus()
             
         switch status {
             case .authorized:
                 // 已经授权，继续访问相册
             DispatchQueue.main.async {
                 self.showPhotoLibrary()
             }
                 
             case .denied, .restricted:
                 // 用户拒绝或受限，无法访问相册
                 print("用户拒绝访问相册")
             case .notDetermined:
                 // 用户还没有决定是否允许访问，进行请求
                 PHPhotoLibrary.requestAuthorization { newStatus in
                     if newStatus == .authorized {
                         // 用户授权，继续访问相册
                         DispatchQueue.main.async {
                             self.showPhotoLibrary()
                         }
                     } else {
                         print("用户拒绝访问相册")
                     }
                 }
         @unknown default:
                 print("未知的权限状态")
         }
     }
     
     private func showPhotoLibrary() {
         
         let config = ZLPhotoConfiguration.default()
         
         config.languageType = .chineseSimplified
         config.allowSelectGif = false
         config.allowMixSelect = false
         config.allowTakePhotoInLibrary = true
         config.allowEditVideo = true
         config.maxEditVideoTime = .max
         config.maxRecordDuration = .max
         config.maxSelectVideoDuration = .max
         config.saveNewImageAfterEdit = false
         config.editAfterSelectThumbnailImage = true
         config.allowSelectOriginal = false
         config.animateSelectBtnWhenSelect = false
         config.cropVideoAfterSelectThumbnail = true
         config.saveNewImageAfterEdit = false
         if type == 1 {
             config.allowSelectVideo = false
             config.allowSelectImage = true
             config.maxSelectCount = 9
         }else{
             config.allowSelectVideo = true
             config.allowSelectImage = false
             config.maxSelectCount = 0
         }
         
         let ac = ZLPhotoPreviewSheet(selectedAssets:assets)
         
         ac.selectImageBlock = { [weak self] (images, assets, isOriginal) in
             self?.images = images
             self?.assets = assets
             self?.loadImageData()
         }
         ac.showPhotoLibrary(sender: self)
     }
     
     @objc private func clickSendButton(){

         let fullText = NSMutableString()
         textView.attributedText.enumerateAttributes(in: NSRange(location: 0, length: textView.attributedText.length), options: []) { attributes, range, _ in
             if attributes[.attachment] is NSTextAttachment {
                 // 发现图片，添加占位符 "[图片]"
                 fullText.append("[图片]")
             } else {
                 // 纯文本部分，直接追加到 fullText 中
                 let substring = (textView.attributedText.string as NSString).substring(with: range)
                 fullText.append(substring)
             }
         }
         let titleText = titleTextField.text ?? ""
         let contentText = textView.text ?? ""
         
         if titleText.count <= 0 {
             "请输入发布标题".toast_error
             return
         }
         if contentText.count <= 0 {
             "请输入发布内容".toast_error
             return
         }
         ToastUtil.show()
         if type != 1 {
             ZLPhotoManager.fetchAssetFilePath(asset: self.assets.first!) { path in
                 let movURL = URL(fileURLWithPath: path ?? "")
                 self.convertMovToMp4Data(inputURL: movURL) { result in
                     switch result {
                     case .success(let mp4Data):
                         let suffix = "MP4"
                         RaeRequestParameterConfig.shared.uploadImage(uploadImage: self.images.first!) { urlString in
                             RaeRequestParameterConfig.shared.uploadVideo(record: mp4Data, suffix: suffix) { videoUrl in
                                 self.addDynamic(title: titleText, content: fullText as String, imgs: urlString, video: videoUrl)
                             } failure: { errorMessage in
                                 ToastUtil.dismiss()
                                 errorMessage.toast_error
                             } progress: { pro in
                                 
                             }

                         } failure: { errorMessage in
                             ToastUtil.dismiss()
                         }
                     case .failure(let error):
                         print("转换失败：\(error.localizedDescription)")
                     }
                 }
             }
         }else{
             if self.images.count > 0 {
                 updateImage(title: titleText, content: fullText as String)
             }else{
                 addDynamic(title: titleText, content: fullText as String, imgs: "", video: "")
             }
         }
     }
     
     private func addDynamic(title: String, content: String, imgs: String, video: String){
         
         Task{
             self.subject_id.removeAll()
             self.gid.removeAll()
             self.post_id.removeAll()
             for md in tempArray {
                 if md.type == "1" {
                     subject_id.append(md.id)
                 }else if md.type == "2" {
                     gid.append(md.id)
                 }else if md.type == "3" {
                     post_id.append(md.id)
                 }
             }
             let subject_String = self.subject_id.joined(separator: ",")
             let gid_string = self.gid.joined(separator: ",")
             let news_id = self.post_id.joined(separator: ",")
             let dict: [String: String] = ["content": content, "image": imgs, "video": video, "subject_id": subject_String, "gid": gid_string, "pid": self.communityId, "class_id": self.classID, "title": title, "news_id": news_id]
             let res = await self.network.requestSpecial(.pushCommunityPost(json: dict),isShowError: true, .post)
             ToastUtil.dismiss()
             if res.isSuccess {
                 self.updateDataBlock?()
                 if self.fromDraft {
                     if self.type == 1 {
                         UserDefaultsManager.removeForKey(forKey: .picForumPost)
                     }else{
                         UserDefaultsManager.removeForKey(forKey: .videoForumPost)
                     }
                 }
                 self.images.removeAll()
                 self.assets.removeAll()
                 self.dismiss(animated: true)
             }else{
                 res.errorMessage?.toast_error
             }
         }
     }
     
     private func updateImage(title: String, content: String){
         self.imageUrlArr.removeAll()
         let upLoadImageGroup = DispatchGroup()
         let workingQueue = DispatchQueue(label: "upLoadImageGroup")
         for i in 0..<images.count {
             upLoadImageGroup.enter()
             
             workingQueue.async {

                 RaeRequestParameterConfig.shared.uploadImage(uploadImage: self.images[i]) { urlString in
                     self.imageUrlArr.append(urlString)
                     upLoadImageGroup.leave()
                 } failure: { errorMessage in
                     upLoadImageGroup.leave()
                 }
             }
         }         
         upLoadImageGroup.notify(queue: workingQueue) {
             self.addDynamic(title: title, content: content, imgs: self.imageUrlArr.joined(separator: ","), video: "")
         }
     }
    
    @objc private func clickCloseButton(){
        
        if isShowDraftView() {
            
            let draftView = ClubPushForumDraftAlertView()
            draftView.discardBlock = {
                self.dismiss(animated: true)
            }
            draftView.saveBlock = {
                self.saveToDraft()
            }
            self.entryAnimate.animation(show: draftView)
        }else{
         
            self.dismiss(animated: true)
        }
    }
    
    private func isShowDraftView() -> Bool{
        
        let titleText = titleTextField.text ?? ""
        let contentText = textView.text ?? ""
        
        if titleText.count > 0 || contentText.count > 0 || self.images.count > 0 || self.subject_id.count > 0 || self.gid.count > 0 || self.post_id.count > 0 {
            return true
        }
        return false
    }
    
    private func saveToDraft(){
        
        var dictionary = [String: Any]()
        
        let fullText = NSMutableString()
        textView.attributedText.enumerateAttributes(in: NSRange(location: 0, length: textView.attributedText.length), options: []) { attributes, range, _ in
            if attributes[.attachment] is NSTextAttachment {
                // 发现图片，添加占位符 "[图片]"
                fullText.append("[图片]")
            } else {
                // 纯文本部分，直接追加到 fullText 中
                let substring = (textView.attributedText.string as NSString).substring(with: range)
                fullText.append(substring)
            }
        }
        let titleText = titleTextField.text ?? ""
        let subject_String = self.subject_id.joined(separator: ",")
        let gid_string = self.gid.joined(separator: ",")
        let news_id = self.post_id.joined(separator: ",")
        let assetIdentifiers = assets.map { $0.localIdentifier }
        let imageDataArray = images.compactMap { $0.pngData() }
        let ranges = richTextRange.map { ["location": $0.location, "length": $0.length] }
        
        dictionary["title"] = titleText
        dictionary["content"] = fullText as String
        dictionary["images"] = imageDataArray
        dictionary["assets"] = assetIdentifiers
        dictionary["subject_id"] = subject_String
        dictionary["gid"] = gid_string
        dictionary["news_id"] = news_id
        dictionary["type"] = type
        dictionary["time"] = Date().toString(.yearMonthDayHourMinuteSecond)
        dictionary["communityId"] = communityId
        dictionary["ranges"] = ranges
        var tempModels = [ClubTempDynamicGameModel]()
        for mm in tempArray {
            let mod = mm.toTempModel()
            tempModels.append(mod)
        }
        do {
            // 将对象数组编码为 Data
            let encodedData = try JSONEncoder().encode(tempModels)
            // 存储到 UserDefaults
            dictionary["models"] = encodedData
        } catch {
           
        }
        
        if type == 1 {
            UserDefaultsManager.setDict(dictionary, forKey: .picForumPost)
        }else{
            UserDefaultsManager.setDict(dictionary, forKey: .videoForumPost)
        }
        self.dismiss(animated: true)
    }
    
    private func updateSendState(){
        
        if let title = titleTextField.text, title.count > 0 && !textView.text.isEmpty {
            sendButton.isEnabled = true
        }else{
            sendButton.isEnabled = false
        }
    }

    //Mov to mp4
    func convertMovToMp4Data(inputURL: URL, completion: @escaping (Result<Data, Error>) -> Void) {
        // 生成临时输出文件的路径
        let outputURL = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(UUID().uuidString).appendingPathExtension("mp4")

        // 创建 AVAsset
        let asset = AVAsset(url: inputURL)

        // 创建导出会话
        guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetMediumQuality) else {
            completion(.failure(NSError(domain: "ExportSessionCreation", code: -1, userInfo: [NSLocalizedDescriptionKey: "Failed to create AVAssetExportSession."])))
            return
        }

        exportSession.outputFileType = .mp4
        exportSession.outputURL = outputURL
        exportSession.shouldOptimizeForNetworkUse = true

        // 开始导出
        exportSession.exportAsynchronously {
            defer {
                // 无论成功与否都清理临时文件
                try? FileManager.default.removeItem(at: outputURL)
            }

            switch exportSession.status {
            case .completed:
                do {
                    // 将文件转换为 Data
                    let data = try Data(contentsOf: outputURL)
                    completion(.success(data))
                } catch {
                    completion(.failure(error))
                }
            case .failed:
                if let error = exportSession.error {
                    completion(.failure(error))
                } else {
                    completion(.failure(NSError(domain: "ExportFailed", code: -2, userInfo: [NSLocalizedDescriptionKey: "Export failed with unknown error."])))
                }
            case .cancelled:
                completion(.failure(NSError(domain: "ExportCancelled", code: -3, userInfo: [NSLocalizedDescriptionKey: "Export was cancelled."])))
            default:
                completion(.failure(NSError(domain: "ExportUnknown", code: -4, userInfo: [NSLocalizedDescriptionKey: "Export failed with unknown status."])))
            }
        }
    }

}

//MARK: TextView
extension ClubPushForumViewController: UITextViewDelegate, UITextFieldDelegate {
    
    // UITextViewDelegate 方法
    func textViewDidChange(_ textView: UITextView) {
        // 计算文本内容的高度
        let size = CGSize(width: textView.frame.width, height: .infinity)
        let estimatedSize = textView.sizeThatFits(size)
        // 更新高度约束
        if estimatedSize.height > 248.0.Scale {
            textView.heightConstraint?.constant = 248.0.Scale
        }else{
            textView.heightConstraint?.constant = estimatedSize.height
        }
        
        // 根据内容决定是否隐藏占位符
        placeholderLabel.isHidden = !textView.text.isEmpty
        updateSendState()
        changeToRichText(textView)
    }
    
    func textViewDidBeginEditing(_ textView: UITextView) {
        // 开始编辑时隐藏占位符
        placeholderLabel.isHidden = true
    }
        
    func textViewDidEndEditing(_ textView: UITextView) {
        // 结束编辑时，如果内容为空，显示占位符
        if textView.text.isEmpty {
            placeholderLabel.isHidden = false
        }
    }
    
    // 监听删除操作
    func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
        if text.isEmpty { // 是删除操作
            for (index, richRange) in richTextRange.enumerated() {
                if NSIntersectionRange(richRange, range).length > 0 {
                // 确保 richRange 不越界
                if richRange.location < textView.textStorage.length {
                    let adjustedRange = NSIntersectionRange(richRange, NSRange(location: 0, length: textView.textStorage.length))
                        textView.textStorage.deleteCharacters(in: adjustedRange)
                        self.tempArray = tempArray.filter { $0.range != richRange }
                        richTextRange.remove(at: index)
                        self.oldText = textView.attributedText
                    }
                    return false
                }
            }
        }
        return true
    }

    func findSpecialRange(at location: Int, in attributedText: NSAttributedString, color: UIColor) -> NSRange {
        let fullText = attributedText.string as NSString
        let length = fullText.length

        // 向前找到特殊文本块的开始
        var startIndex = location
        while startIndex > 0 {
            let attributes = attributedText.attributes(at: startIndex, effectiveRange: nil)
            if attributes[.foregroundColor] as? UIColor != color{
                break
            }
            startIndex -= 1
        }

        // 向后找到特殊文本块的结束
        var endIndex = location
        while endIndex < length {
            let attributes = attributedText.attributes(at: endIndex, effectiveRange: nil)
            if attributes[.foregroundColor] as? UIColor != color {
                break
            }
            endIndex += 1
        }

        // 计算完整范围
        return NSRange(location: startIndex, length: endIndex - startIndex)
    }
    
    func changeToRichText(_ textView: UITextView) {
        guard let selectedRange = textView.selectedTextRange else { return }

        // 获取当前输入方式是否为拼音输入，避免中断拼音输入
        if textView.markedTextRange != nil {
            // 如果有标记文字（拼音输入未完成），不进行富文本更新
            return
        }

        // 获取新的 attributedText
        let currentAttributedText = NSMutableAttributedString(attributedString: textView.attributedText)
//        let newText = textView.text
        
        // 确保 oldText 不为空
        guard let oldText = self.oldText?.string else {
            self.oldText = currentAttributedText
            return
        }
        
        let count = currentAttributedText.string.count - oldText.count
        if count <= 0 {
            return
        }
        
        // 获取新增的文本
        let range = textView.offset(from: textView.beginningOfDocument, to: selectedRange.start)
        let inputRange = NSRange(location: range - count, length: count)
        
        // 判断新输入内容是否为 emoji
        let newInput = (textView.text as NSString).substring(with: inputRange)
        if isEmoji(newInput) {
            // 对于 emoji 的特殊处理
            return
        }
        
        // 设置新输入字符的默认样式
        let newAttributedString = NSAttributedString(string: newInput, attributes: [
            .font: 15.font_regular!,
            .foregroundColor: "#47494D".toColor
        ])
        
        // 替换未设置样式的文本
        currentAttributedText.replaceCharacters(in: inputRange, with: newAttributedString)
        
        // 更新 textView 的 attributedText，并恢复光标位置
        textView.attributedText = currentAttributedText
        self.oldText = currentAttributedText
        if let newPosition = textView.position(from: textView.beginningOfDocument, offset: range) {
            textView.selectedTextRange = textView.textRange(from: newPosition, to: newPosition)
        }
    }

    // 判断是否为 emoji
    func isEmoji(_ text: String) -> Bool {
        return text.unicodeScalars.contains { $0.properties.isEmojiPresentation }
    }

    
    func insertRichText(in textView: UITextView, image: UIImage?, model: ClubDynamicGameModel, textColor: UIColor, imageSize: CGSize) {
        // 创建富文本
        let richText = NSMutableAttributedString()
        var md = model
        var text = model.name + " "
        if model.type == "1" {
            text = " #" + model.name + " "
        }else if model.type == "3" {
            text = " +" + model.title + " "
        }
        var startIndex = 0
        // 添加现有内容
        if let currentText = textView.attributedText {
            richText.append(currentText)
            startIndex = currentText.length
        }

        let gameText = NSMutableAttributedString()
        // 插入图片
        if let image = image {
            gameText.append(NSAttributedString(string: " "))
            let attachment = NSTextAttachment()
            attachment.image = image
            attachment.bounds = CGRect(x: 0, y: -7, width: imageSize.width, height: imageSize.height)
            let imageString = NSAttributedString(attachment: attachment)
            gameText.append(imageString)
        }
        
        // 插入文本
        let attributedText = NSAttributedString(string: text, attributes: [.foregroundColor: textColor])
        gameText.append(attributedText)
        // 记录这个富文本块的范围
      
        let range = NSRange(location: startIndex, length: gameText.length)
        richTextRange.append(range)
        md.range = range
        self.tempArray.append(md)
        
        richText.append(gameText)
        // 保持现有的字体设置
        let entireRange = NSRange(location: 0, length: richText.length)
        richText.addAttribute(.font, value: 15.font_regular!, range: entireRange)

        // 插入后的光标位置
        let newCursorPosition = richText.length

        // 更新UITextView的内容并设置光标位置
        textView.attributedText = richText
        self.oldText = richText
        if let newPosition = textView.position(from: textView.beginningOfDocument, offset: newCursorPosition) {
            textView.selectedTextRange = textView.textRange(from: newPosition, to: newPosition)
        }
        
        // 计算文本内容的高度
        let size = CGSize(width: textView.frame.width, height: .infinity)
        let estimatedSize = textView.sizeThatFits(size)
        // 更新高度约束
        textView.heightConstraint?.constant = estimatedSize.height
    }

    // 监听光标变化
    func textViewDidChangeSelection(_ textView: UITextView) {
        for richRange in richTextRange {
            // 检查光标是否进入了某个富文本块的范围
            if NSLocationInRange(textView.selectedRange.location, richRange) {
                // 如果光标位于富文本内部，移动到富文本块的后面
                let newLocation = richRange.location + richRange.length
                if textView.selectedRange.location < newLocation {
                    textView.selectedRange = NSRange(location: newLocation, length: 0)
                }
            }
        }
    }

    func updateRichTextRanges(){
        var tempRange = richTextRange
        for richRange in richTextRange {
            var rang = richRange
            rang.location -= 1
            tempRange.append(rang)
        }
        richTextRange = tempRange
    }
    
    // 监听输入变化
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        self.updateSendButtonState()
        return true // 返回 true 允许输入
    }

    private func updateSendButtonState(){
        
        if (titleTextField.text?.count ?? 0) > 0 && self.textView.text.count > 0 {
            sendButton.isEnabled = true
        }else{
            sendButton.isEnabled = false
        }
    }
}

//MARK: UICollectionViewDelegate, UICollectionViewDataSource
extension ClubPushForumViewController: UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout {
    
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        
        return images.count
    }
    
    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        guard let pageCell = collectionView.dequeueReusableCell(withReuseIdentifier: ClubGameCircleCell.description(), for: indexPath) as? ClubGameCircleCell else { return UICollectionViewCell() }
        pageCell.imageView.image = images[indexPath.row]
        pageCell.playImage.isHidden = type == 1
        pageCell.index = indexPath.row
        pageCell.delButton.isHidden = false
        pageCell.delBlock = { delIndex in
            self.images.remove(at: delIndex)
            self.assets.remove(at: delIndex)
            self.collectionView.reloadData()
        }
        pageCell.layoutIfNeeded()
        if images.count == 1 {
            pageCell.imageView.addCorner(conrners: [.topLeft,.bottomLeft,.topRight,.bottomRight], radius: 8.0.Scale)
        }else if images.count == 2 {
            if indexPath.row == 0 {
                pageCell.imageView.addCorner(conrners: [.topLeft,.bottomLeft], radius: 8.0.Scale)
            }else {
                pageCell.imageView.addCorner(conrners: [.topRight,.bottomRight], radius: 8.0.Scale)
            }
        }else if images.count == 3 {
            if indexPath.row == 0 {
                pageCell.imageView.addCorner(conrners: [.topLeft,.bottomLeft], radius: 8.0.Scale)
            }else if indexPath.row == 2{
                pageCell.imageView.addCorner(conrners: [.topRight,.bottomRight], radius: 8.0.Scale)
            }else {
                pageCell.imageView.addCorner(conrners: [.topLeft,.bottomLeft,.topRight,.bottomRight], radius: 0)
            }
        }else if images.count == 4 || images.count == 5{
            if indexPath.row == 0 {
                pageCell.imageView.addCorner(conrners: [.topLeft], radius: 8.0.Scale)
            }else if indexPath.row == 2{
                pageCell.imageView.addCorner(conrners: [.topRight], radius: 8.0.Scale)
            }else if indexPath.row == 3 {
                pageCell.imageView.addCorner(conrners: [.bottomLeft], radius: 8.0.Scale)
            }else{
                pageCell.imageView.addCorner(conrners: [.topLeft,.bottomLeft,.topRight,.bottomRight], radius: 0)
            }
            
        }else if images.count == 6 {
            if indexPath.row == 0 {
                pageCell.imageView.addCorner(conrners: [.topLeft], radius: 8.0.Scale)
            }else if indexPath.row == 2{
                pageCell.imageView.addCorner(conrners: [.topRight], radius: 8.0.Scale)
            }else if indexPath.row == 3 {
                pageCell.imageView.addCorner(conrners: [.bottomLeft], radius: 8.0.Scale)
            }else if indexPath.row == 5 {
                pageCell.imageView.addCorner(conrners: [.bottomRight], radius: 8.0.Scale)
            }else{
                pageCell.imageView.addCorner(conrners: [.topLeft,.bottomLeft,.topRight,.bottomRight], radius: 0)
            }
        }else if images.count == 7 || images.count == 8{
            if indexPath.row == 0 {
                pageCell.imageView.addCorner(conrners: [.topLeft], radius: 8.0.Scale)
            }else if indexPath.row == 2{
                pageCell.imageView.addCorner(conrners: [.topRight], radius: 8.0.Scale)
            }else if indexPath.row == 6 {
                pageCell.imageView.addCorner(conrners: [.bottomLeft], radius: 8.0.Scale)
            }else{
                pageCell.imageView.addCorner(conrners: [.topLeft,.bottomLeft,.topRight,.bottomRight], radius: 0)
            }
        }else {
            if indexPath.row == 0 {
                pageCell.imageView.addCorner(conrners: [.topLeft], radius: 8.0.Scale)
            }else if indexPath.row == 2{
                pageCell.imageView.addCorner(conrners: [.topRight], radius: 8.0.Scale)
            }else if indexPath.row == 6 {
                pageCell.imageView.addCorner(conrners: [.bottomLeft], radius: 8.0.Scale)
            }else if indexPath.row == 8 {
                pageCell.imageView.addCorner(conrners: [.bottomRight], radius: 8.0.Scale)
            }else{
                pageCell.imageView.addCorner(conrners: [.topLeft,.bottomLeft,.topRight,.bottomRight], radius: 0)
            }
        }
        
        return pageCell
    }
    
    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        
        if type != 1 {
            return CGSize (width: CGFloat.screenWidth - 72.0.Scale, height: 152.0.Scale)
        }else if images.count == 1 {
            return CGSize (width: CGFloat.screenWidth - 72.0.Scale, height: 152.0.Scale)
        }else if images.count == 2{
            
            return CGSize (width: (CGFloat.screenWidth - 74.0.Scale)/2.0, height: 90.0.Scale)
        }else{
            
            return CGSize (width: (CGFloat.screenWidth - 76.0.Scale)/3, height: (CGFloat.screenWidth - 76.0.Scale)/3)
        }
        
    }
    
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        
        let vc = ZLImagePreviewController(datas: self.assets, index: indexPath.row, showSelectBtn: false) { (url) -> ZLURLType in
            if self.type != 1 {
                return .video
            }else {
                return .image
            }
            
        } urlImageLoader: { (url, imageView, progress, loadFinish) in
            imageView.kf.setImage(with: url) { (receivedSize, totalSize) in
                let percentage = (CGFloat(receivedSize) / CGFloat(totalSize))
                debugPrint("\(percentage)")
                progress(percentage)
            } completionHandler: { (_) in
                loadFinish()
            }
        }
        vc.modalPresentationStyle = .fullScreen
        self.showDetailViewController(vc, sender: nil)
    }
}


//MARK: data
extension ClubPushForumViewController {
        
    private func loadImageData(){
        
        if type != 1 {
            
            collectionView.heightConstraint?.constant = 152.0.Scale
        }else {
            
            if images.count == 1 {
                collectionView.heightConstraint?.constant = 152.0.Scale
            }else if images.count == 2 {
                collectionView.heightConstraint?.constant = 90.0.Scale
            }else if images.count > 2 {
                let index = (images.count + 2) / 3
                collectionView.heightConstraint?.constant = (CGFloat.screenWidth - 76.0.Scale)/3 * CGFloat(index)
            }else{
                collectionView.heightConstraint?.constant = 0
            }
        }
        collectionView.reloadData()
    }
    
    private func createAttributedText(from text: String) -> NSMutableAttributedString {

        let attributedString = NSMutableAttributedString(string: text)
        attributedString.addAttribute(.foregroundColor, value: "#47494D".toColor, range: NSRange(location: 0, length: attributedString.length))
        attributedString.addAttribute(.font, value: 15.font_regular!, range: NSRange(location: 0, length: attributedString.length))
        
        let nsText = text as NSString
        var count = 0
        var offset = 0 // 偏移量
        
        // 正则匹配 [图片] 和 #标签
        let hashtagRegex = try! NSRegularExpression(pattern: "#[^\\s]+", options: [])
        let imageTextRegex = try! NSRegularExpression(pattern: "\\[图片\\](\\S+?) ", options: [])
        let postTagRegex = try! NSRegularExpression(pattern: "\\+\\S+", options: [])
        
        // **1. 优先处理 #标签**
        let hashtagMatches = hashtagRegex.matches(in: text, options: [], range: NSRange(location: 0, length: nsText.length))
        for match in hashtagMatches {
            let matchRange = match.range(at: 0)
            guard matchRange.location != NSNotFound else { continue }
            
            let hashtagRange = NSRange(location: matchRange.location + offset, length: matchRange.length)
            guard hashtagRange.location >= 0,
                  hashtagRange.location + hashtagRange.length <= attributedString.length else { continue }
            if var substring = attributedString.attributedSubstring(from: hashtagRange).string as String? {
                if substring.hasPrefix("#") {
                    substring.removeFirst()
                }
                if tempArray.contains(where: { $0.name == substring }) {
                    attributedString.addAttribute(.foregroundColor, value: "#E57617".toColor, range: hashtagRange) // 橙色
                }
            }
        }
        
        // **2. 优先处理 +标签**
        let posttagMatches = postTagRegex.matches(in: text, options: [], range: NSRange(location: 0, length: nsText.length))
        for match in posttagMatches {
            let matchRange = match.range(at: 0)
            guard matchRange.location != NSNotFound else { continue }
            
            let posttagRange = NSRange(location: matchRange.location + offset, length: matchRange.length)
            guard posttagRange.location >= 0,
                  posttagRange.location + posttagRange.length <= attributedString.length else { continue }
            if var substring = attributedString.attributedSubstring(from: posttagRange).string as String? {
                if substring.hasPrefix("+") {
                    substring.removeFirst()
                }
                if tempArray.contains(where: { $0.title == substring }) {
                    attributedString.addAttribute(.foregroundColor, value: "#1280E5".toColor, range: posttagRange) // 橙色
                }
            }
        }
        
        // **3. 处理 [图片]**
        let imageTextMatches = imageTextRegex.matches(in: text, options: [], range: NSRange(location: 0, length: nsText.length))
        for match in imageTextMatches {
            let fullMatchRange = NSRange(location: match.range(at: 0).location + offset, length: match.range(at: 0).length)
            let textRange = NSRange(location: match.range(at: 1).location + offset, length: match.range(at: 1).length)
            
            // 替换 [图片] 为图片
            let attachment = NSTextAttachment()
            attachment.image = UIImage(named: "Square_gameTag") // 替换为图片
            attachment.bounds = CGRect(x: 0, y: -7, width: 20, height: 20)
            let imageString = NSAttributedString(attachment: attachment)
            
            attributedString.replaceCharacters(in: NSRange(location: fullMatchRange.location, length: "[图片]".count), with: imageString)
            offset += imageString.length - "[图片]".count // 更新偏移量
            
            // 设置图片后面的文字颜色
            let updatedTextRange = NSRange(location: textRange.location + offset + (3 * count), length: textRange.length)
            if updatedTextRange.location + updatedTextRange.length <= attributedString.length {
                attributedString.addAttribute(.foregroundColor, value: "#3D9399".toColor, range: updatedTextRange)
            }
            count += 1
        }
        return attributedString
    }

}
